home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / hity wydania / Ubuntu 9.10 PL / karmelkowy-koliberek-desktop-9.10-i386-PL.iso / casper / filesystem.squashfs / usr / share / pyshared / DistUpgrade / DistUpgradeQuirks.py < prev    next >
Text File  |  2009-11-02  |  47KB  |  978 lines

  1. # DistUpgradeQuirks.py 
  2. #  
  3. #  Copyright (c) 2004-2008 Canonical
  4. #  
  5. #  Author: Michael Vogt <michael.vogt@ubuntu.com>
  6. #  This program is free software; you can redistribute it and/or 
  7. #  modify it under the terms of the GNU General Public License as 
  8. #  published by the Free Software Foundation; either version 2 of the
  9. #  License, or (at your option) any later version.
  10. #  This program is distributed in the hope that it will be useful,
  11. #  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. #  GNU General Public License for more details.
  14. #  You should have received a copy of the GNU General Public License
  15. #  along with this program; if not, write to the Free Software
  16. #  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  17. #  USA
  18.  
  19. import glob
  20. import logging
  21. import os
  22. import os.path
  23. import re
  24. import shutil
  25. import string
  26. import sys
  27. import subprocess
  28. from subprocess import PIPE, Popen, call
  29. from hashlib import md5
  30. from utils import lsmod
  31.  
  32. from DistUpgradeGettext import gettext as _
  33. from DistUpgradeGettext import ngettext
  34. import gettext
  35.  
  36. from computerjanitor.plugin import PluginManager
  37.  
  38. class DistUpgradeQuirks(object):
  39.     """
  40.     This class collects the various quirks handlers that can
  41.     be hooked into to fix/work around issues that the individual
  42.     releases have
  43.     """
  44.     
  45.     def __init__(self, controller, config):
  46.         self.controller = controller
  47.         self._view = controller._view
  48.         self.config = config
  49.         self.uname = Popen(["uname","-r"],stdout=PIPE).communicate()[0].strip()
  50.         self.arch = Popen(["dpkg", "--print-architecture"], stdout=PIPE).communicate()[0]
  51.         self.plugin_manager = PluginManager(self.controller, ["./plugins"])
  52.  
  53.     # the quirk function have the name:
  54.     #  $Name (e.g. PostUpgrade)
  55.     #  $todist$Name (e.g. intrepidPostUpgrade)
  56.     #  $from_$fromdist$Name (e.g. from_dapperPostUpgrade)
  57.     def run(self, quirksName):
  58.         """
  59.         Run the specific quirks handler, the follow handlers are supported:
  60.         - PostInitialUpdate: run *before* the sources.list is rewritten but
  61.                              after a initial apt-get update
  62.         - PostDistUpgradeCache: run *after* the dist-upgrade was calculated
  63.                                 in the cache
  64.         - StartUpgrade: before the first package gets installed (but the
  65.                         download is finished)
  66.         - PostUpgrade: run *after* the upgrade is finished successfully and 
  67.                        packages got installed
  68.         - PostCleanup: run *after* the cleanup (orphaned etc) is finished
  69.         """
  70.         # we do not run any quirks in partialUpgrade mode
  71.         if self.controller._partialUpgrade:
  72.             logging.info("not running quirks in partialUpgrade mode")
  73.             return
  74.         # first check for matching plugins
  75.         for condition in [
  76.             quirksName,
  77.             "%s%s" %  (self.config.get("Sources","To"), quirksName),
  78.             "from_%s%s" % (self.config.get("Sources","From"), quirksName)
  79.             ]:
  80.             for plugin in self.plugin_manager.get_plugins(condition):
  81.                 logging.debug("running quirks plugin %s" % plugin)
  82.                 plugin.do_cleanup_cruft()
  83.         
  84.         # run the handler that is common to all dists
  85.         funcname = "%s" % quirksName
  86.         func = getattr(self, funcname, None)
  87.         if func is not None:
  88.             logging.debug("quirks: running %s" % funcname)
  89.             func()
  90.  
  91.         # run the quirksHandler to-dist
  92.         funcname = "%s%s" % (self.config.get("Sources","To"), quirksName)
  93.         func = getattr(self, funcname, None)
  94.         if func is not None:
  95.             logging.debug("quirks: running %s" % funcname)
  96.             func()
  97.  
  98.         # now run the quirksHandler from_${FROM-DIST}Quirks
  99.         funcname = "from_%s%s" % (self.config.get("Sources","From"), quirksName)
  100.         func = getattr(self, funcname, None)
  101.         if func is not None:
  102.             logging.debug("quirks: running %s" % funcname)
  103.             func()
  104.  
  105.     # individual quirks handler when the dpkg run is finished ---------
  106.     def PostCleanup(self):
  107.         " run after cleanup " 
  108.         logging.debug("running Quirks.PostCleanup")
  109.  
  110.     def from_dapperPostUpgrade(self):
  111.         " this works around quirks for dapper->hardy upgrades "
  112.         logging.debug("running Controller.from_dapperQuirks handler")
  113.         self._rewriteFstab()
  114.         self._checkAdminGroup()
  115.         
  116.     def intrepidPostUpgrade(self):
  117.         " this applies rules for the hardy->intrepid upgrade "
  118.     logging.debug("running Controller.intrepidQuirks handler")
  119.         self._addRelatimeToFstab()
  120.  
  121.     def gutsyPostUpgrade(self):
  122.         """ this function works around quirks in the feisty->gutsy upgrade """
  123.         logging.debug("running Controller.gutsyQuirks handler")
  124.  
  125.     def feistyPostUpgrade(self):
  126.         """ this function works around quirks in the edgy->feisty upgrade """
  127.         logging.debug("running Controller.feistyQuirks handler")
  128.         self._rewriteFstab()
  129.         self._checkAdminGroup()
  130.  
  131.     def karmicPostUpgrade(self):
  132.         """ this function works around quirks in the jaunty->karmic upgrade """
  133.         logging.debug("running Controller.karmicPostUpgrade handler")
  134.         self._ntfsFstabFixup()
  135.         self._checkLanguageSupport()
  136.  
  137.     # quirks when run when the initial apt-get update was run -------
  138.     def karmicPostInitialUpdate(self):
  139.         " quirks that are run before the upgrade to karmic "
  140.         logging.debug("running %s" %  sys._getframe().f_code.co_name)
  141.         # we switched the supported CPU arches for armel to a minimal of ARMv6.
  142.         # upgrades on systems with CPUs not matching this minimum will break
  143.         # on karmic
  144.         if self.arch == "armel":
  145.             if not self._checkArmCPU():
  146.                 res = self._view.error(_("No ARMv6 CPU"),
  147.                     _("Your system uses an ARM CPU that is older "
  148.                       "than the ARMv6 architecture. "
  149.                       "All packages in karmic were built with "
  150.                       "optimizations requiring ARMv6 as the "
  151.                       "minimal architecture. It is not possible to "
  152.                       "upgrade your system to a new Ubuntu release "
  153.                       "with this hardware."))
  154.                 self.controller.abort()
  155.         # verver test (LP: #454783), see if there is a init around
  156.         try:
  157.             os.kill(1, 0)
  158.         except:
  159.             logging.warn("no init found")
  160.             res = self._view.askYesNoQuestion(
  161.                 _("No init available"),
  162.                 _("Your system appears to be a virtualised environment "
  163.                   "without an init daemon, e.g. Linux-VServer. "
  164.                   "Ubuntu 9.10 cannot function within this type of "
  165.                   "environment, requiring an update to your virtual "
  166.                   "machine configuration first.\n\n"
  167.                   "Are you sure you want to continue?"))
  168.             if res == False:
  169.                 self.controller.abort()
  170.             self._view.processEvents()
  171.  
  172.     # fglrx is broken in intrepid (no support for xserver 1.5)
  173.     def jauntyPostInitialUpdate(self):
  174.         " quirks that are run before the upgrade to jaunty "
  175.         logging.debug("running %s" %  sys._getframe().f_code.co_name
  176. )
  177.         # this is to deal with the fact that support for some of the cards
  178.         # that fglrx used to support got dropped
  179.         if (self._checkVideoDriver("fglrx") and 
  180.             not self._supportInModaliases("fglrx")):
  181.              # TRANSLATORS: this string is not displayed in the 9.10 upgrade
  182.              #              (but it will be used for 8.04 -> 10.04 LTS upgrades)
  183.              res = self._view.askYesNoQuestion(_("Upgrading may reduce desktop "
  184.                                          "effects, and performance in games "
  185.                                          "and other graphically intensive "
  186.                                          "programs."),
  187.                                        _("This computer is currently using "
  188.                                          "the AMD 'fglrx' graphics driver. "
  189.                                          "No version of this driver is "
  190.                                          "available that works with your "
  191.                                          "hardware in Ubuntu "
  192.                                          "10.04.\n\nDo you want to continue?"))
  193.              if res == False:
  194.                  self.controller.abort()
  195.              # if the user wants to continue we remove the fglrx driver
  196.              # here because its no use (no support for this card)
  197.              logging.debug("remove xorg-driver-fglrx,xorg-driver-fglrx-envy,fglrx-kernel-source")
  198.              l=self.controller.config.getlist("Distro","PostUpgradePurge")
  199.              l.append("xorg-driver-fglrx")
  200.              l.append("xorg-driver-fglrx-envy")
  201.              l.append("fglrx-kernel-source")
  202.              l.append("fglrx-amdcccle")
  203.              l.append("xorg-driver-fglrx-dev")
  204.              l.append("libamdxvba1")
  205.              self.controller.config.set("Distro","PostUpgradePurge",",".join(l))
  206.  
  207.     # quirks when the cache upgrade calculation is finished
  208.     def from_dapperPostDistUpgradeCache(self):
  209.         self.hardyPostDistUpgradeCache()
  210.         self.gutsyPostDistUpgradeCache()
  211.         self.feistyPostDistUpgradeCache()
  212.         self.edgyPostDistUpgradeCache()
  213.  
  214.     def from_hardyPostDistUpgradeCache(self):
  215.         self._kernel386TransitionCheck()
  216.  
  217.     def karmicPostDistUpgradeCache(self):
  218.         """ 
  219.         this function works around quirks in the 
  220.         jaunty->karmic upgrade calculation
  221.         """
  222.         # check if "wl" module is loaded and if so, install
  223.         # bcmwl-kernel-source (this is needed for lts->lts as well)
  224.         self._checkAndInstallBroadcom()
  225.         self._dealWithLanguageSupportTransition()
  226.         self._kernel386TransitionCheck()
  227.         self._mysqlClusterCheck()
  228.  
  229.     def jauntyPostDistUpgradeCache(self):
  230.         """ 
  231.         this function works around quirks in the 
  232.         intrepid->jaunty upgrade calculation
  233.         """
  234.         logging.debug("running %s" %  sys._getframe().f_code.co_name)
  235.         # bug 332328 - make sure pidgin-libnotify is upgraded
  236.         for pkg in ["pidgin-libnotify"]:
  237.             if (self.controller.cache.has_key(pkg) and
  238.                 self.controller.cache[pkg].isInstalled and
  239.                 not self.controller.cache[pkg].markedUpgrade):
  240.                 logging.debug("forcing '%s' upgrade" % pkg)
  241.                 self.controller.cache[pkg].markUpgrade()
  242.         # deal with kipi/gwenview/kphotoalbum
  243.         for pkg in ["gwenview","digikam"]:
  244.             if (self.controller.cache.has_key(pkg) and
  245.                 self.controller.cache[pkg].isInstalled and
  246.                 not self.controller.cache[pkg].markedUpgrade):
  247.                 logging.debug("forcing libkipi '%s' upgrade" % pkg)
  248.                 if self.controller.cache.has_key("libkipi0"):
  249.                     logging.debug("removing  libkipi0)")
  250.                     self.controller.cache["libkipi0"].markDelete()
  251.                 self.controller.cache[pkg].markUpgrade()
  252.         
  253.     def intrepidPostDistUpgradeCache(self):
  254.         """ 
  255.         this function works around quirks in the 
  256.         hardy->intrepid upgrade 
  257.         """
  258.         logging.debug("running %s" %  sys._getframe().f_code.co_name)
  259.         # now check for nvidia and show a warning if needed
  260.         cache = self.controller.cache
  261.         for pkgname in ["nvidia-glx-71","nvidia-glx-96"]:
  262.             if (cache.has_key(pkgname) and 
  263.                 cache[pkgname].markedInstall and
  264.                 self._checkVideoDriver("nvidia")):
  265.                 logging.debug("found %s video driver" % pkgname)
  266.                 # TRANSLATORS: this string is not displayed in the 9.10 upgrade
  267.                 #              (but it will be used for 8.04 -> 10.04 LTS upgrades)
  268.                 res = self._view.askYesNoQuestion(_("Upgrading may reduce desktop "
  269.                                         "effects, and performance in games "
  270.                                         "and other graphically intensive "
  271.                                         "programs."),
  272.                                       _("This computer is currently using "
  273.                                         "the NVIDIA 'nvidia' "
  274.                                         "graphics driver. "
  275.                                         "No version of this driver is "
  276.                                         "available that works with your "
  277.                                         "video card in Ubuntu "
  278.                                         "10.04.\n\nDo you want to continue?"))
  279.                 if res == False:
  280.                     self.controller.abort()
  281.                 # if the user continue, do not install the broken driver
  282.                 # so that we can transiton him to the free "nv" one after
  283.                 # the upgrade
  284.                 self.controller.cache[pkgname].markKeep()
  285.         # check if we have sse
  286.         for pkgname in ["nvidia-glx-173","nvidia-glx-177"]:
  287.             if (cache.has_key(pkgname) and 
  288.                 cache[pkgname].markedInstall and
  289.                 self._checkVideoDriver("nvidia")):
  290.                 logging.debug("found %s video driver" % pkgname)
  291.                 if not self._cpuHasSSESupport():
  292.                     logging.warning("nvidia driver that needs SSE but cpu has no SSE support")
  293.                     # TRANSLATORS: this string is not displayed in the 9.10 upgrade
  294.                     #              (but it will be used for 8.04 -> 10.04 LTS upgrades)
  295.                     res = self._view.askYesNoQuestion(_("Upgrading may reduce desktop "
  296.                                         "effects, and performance in games "
  297.                                         "and other graphically intensive "
  298.                                         "programs."),
  299.                                       _("This computer is currently using "
  300.                                         "the NVIDIA 'nvidia' "
  301.                                         "graphics driver. "
  302.                                         "No version of this driver is "
  303.                                         "available that works with your "
  304.                                         "video card in Ubuntu "
  305.                                         "10.04.\n\nDo you want to continue?"))
  306.                     if res == False:
  307.                         self.controller.abort()
  308.                     # if the user continue, do not install the broken driver
  309.                     # so that we can transiton him to the free "nv" one after
  310.                     # the upgrade
  311.                     self.controller.cache[pkgname].markKeep()
  312.         # kdelibs4-dev is unhappy (#279621)
  313.         fromp = "kdelibs4-dev"
  314.         to = "kdelibs5-dev"
  315.         if (self.controller.cache.has_key(fromp) and 
  316.             self.controller.cache[fromp].isInstalled and
  317.             self.controller.cache.has_key(to)):
  318.             self.controller.cache.markInstall(to, "kdelibs4-dev -> kdelibs5-dev transition")
  319.  
  320.     def hardyPostDistUpgradeCache(self):
  321.         """ 
  322.         this function works around quirks in the 
  323.         {dapper,gutsy}->hardy upgrade 
  324.         """
  325.         logging.debug("running %s" %  sys._getframe().f_code.co_name)
  326.         # deal with gnome-translator and help apt with the breaks
  327.         if (self.controller.cache.has_key("nautilus") and
  328.             self.controller.cache["nautilus"].isInstalled and
  329.             not self.controller.cache["nautilus"].markedUpgrade):
  330.             # uninstallable and gutsy apt is unhappy about this
  331.             # breaks because it wants to upgrade it and gives up
  332.             # if it can't
  333.             for broken in ("link-monitor-applet"):
  334.                 if self.controller.cache.has_key(broken) and self.controller.cache[broken].isInstalled:
  335.                     self.controller.cache[broken].markDelete()
  336.             self.controller.cache["nautilus"].markInstall()
  337.         # evms gives problems, remove it if it is not in use
  338.         self._checkAndRemoveEvms()
  339.         # give the language-support-* packages a extra kick
  340.         # (if we have network, otherwise this will not work)
  341.         if self.config.get("Options","withNetwork") == "True":
  342.             for pkg in self.controller.cache:
  343.                 if (pkg.name.startswith("language-support-") and
  344.                     pkg.isInstalled and
  345.                     not pkg.markedUpgrade):
  346.                     self.controller.cache.markInstall(pkg.name,"extra language-support- kick")
  347.  
  348.     def gutsyPostDistUpgradeCache(self):
  349.         """ this function works around quirks in the feisty->gutsy upgrade """
  350.         logging.debug("running %s" %  sys._getframe().f_code.co_name)
  351.         # lowlatency kernel flavour vanished from feisty->gutsy
  352.         try:
  353.             (version, build, flavour) = self.uname.split("-")
  354.             if (flavour == 'lowlatency' or 
  355.                 flavour == '686' or
  356.                 flavour == 'k7'):
  357.                 kernel = "linux-image-generic"
  358.                 if not (self.controller.cache[kernel].isInstalled or self.controller.cache[kernel].markedInstall):
  359.                     logging.debug("Selecting new kernel '%s'" % kernel)
  360.                     self.controller.cache[kernel].markInstall()
  361.         except Exception, e:
  362.             logging.warning("problem while transitioning lowlatency kernel (%s)" % e)
  363.         # fix feisty->gutsy utils-linux -> nfs-common transition (LP: #141559)
  364.         try:
  365.             for line in map(string.strip, open("/proc/mounts")):
  366.                 if line == '' or line.startswith("#"):
  367.                     continue
  368.                 try:
  369.                     (device, mount_point, fstype, options, a, b) = line.split()
  370.                 except Exception, e:
  371.                     logging.error("can't parse line '%s'" % line)
  372.                     continue
  373.                 if "nfs" in fstype:
  374.                     logging.debug("found nfs mount in line '%s', marking nfs-common for install " % line)
  375.                     self.controller.cache["nfs-common"].markInstall()
  376.                     break
  377.         except Exception, e:
  378.             logging.warning("problem while transitioning util-linux -> nfs-common (%s)" % e)
  379.  
  380.     def feistyPostDistUpgradeCache(self):
  381.         """ this function works around quirks in the edgy->feisty upgrade """
  382.         logging.debug("running %s" %  sys._getframe().f_code.co_name)
  383.         # ndiswrapper changed again *sigh*
  384.         for (fr, to) in [("ndiswrapper-utils-1.8","ndiswrapper-utils-1.9")]:
  385.             if self.controller.cache.has_key(fr) and self.controller.cache.has_key(to):
  386.                 if self.controller.cache[fr].isInstalled and not self.controller.cache[to].markedInstall:
  387.                     try:
  388.                         self.controller.cache.markInstall(to,"%s->%s quirk upgrade rule" % (fr, to))
  389.                     except SystemError, e:
  390.                         logging.warning("Failed to apply %s->%s install (%s)" % (fr, to, e))
  391.             
  392.  
  393.     def edgyPostDistUpgradeCache(self):
  394.         """ this function works around quirks in the dapper->edgy upgrade """
  395.         logging.debug("running %s" %  sys._getframe().f_code.co_name)
  396.         for pkg in self.controller.cache:
  397.             # deal with the python2.4-$foo -> python-$foo transition
  398.             if (pkg.name.startswith("python2.4-") and
  399.                 pkg.isInstalled and
  400.                 not pkg.markedUpgrade):
  401.                 basepkg = "python-"+pkg.name[len("python2.4-"):]
  402.                 if (self.controller.cache.has_key(basepkg) and 
  403.                     self.controller.cache[basepkg].candidateDownloadable and
  404.                     not self.controller.cache[basepkg].markedInstall):
  405.                     try:
  406.                         self.controller.cache.markInstall(basepkg,
  407.                                          "python2.4->python upgrade rule")
  408.                     except SystemError, e:
  409.                         logging.debug("Failed to apply python2.4->python install: %s (%s)" % (basepkg, e))
  410.             # xserver-xorg-input-$foo gives us trouble during the upgrade too
  411.             if (pkg.name.startswith("xserver-xorg-input-") and
  412.                 pkg.isInstalled and
  413.                 not pkg.markedUpgrade):
  414.                 try:
  415.                     self.controller.cache.markInstall(pkg.name, "xserver-xorg-input fixup rule")
  416.                 except SystemError, e:
  417.                     logging.debug("Failed to apply fixup: %s (%s)" % (pkg.name, e))
  418.             
  419.         # deal with held-backs that are unneeded
  420.         for pkgname in ["hpijs", "bzr", "tomboy"]:
  421.             if (self.controller.cache.has_key(pkgname) and self.controller.cache[pkgname].isInstalled and
  422.                 self.controller.cache[pkgname].isUpgradable and not self.controller.cache[pkgname].markedUpgrade):
  423.                 try:
  424.                     self.controller.cache.markInstall(pkgname,"%s quirk upgrade rule" % pkgname)
  425.                 except SystemError, e:
  426.                     logging.debug("Failed to apply %s install (%s)" % (pkgname,e))
  427.         # libgl1-mesa-dri from xgl.compiz.info (and friends) breaks the
  428.     # upgrade, work around this here by downgrading the package
  429.         if self.controller.cache.has_key("libgl1-mesa-dri"):
  430.             pkg = self.controller.cache["libgl1-mesa-dri"]
  431.             # the version from the compiz repo has a "6.5.1+cvs20060824" ver
  432.             if (pkg.candidateVersion == pkg.installedVersion and
  433.                 "+cvs2006" in pkg.candidateVersion):
  434.                 for ver in pkg._pkg.VersionList:
  435.                     # the "official" edgy version has "6.5.1~20060817-0ubuntu3"
  436.                     if "~2006" in ver.VerStr:
  437.             # ensure that it is from a trusted repo
  438.             for (VerFileIter, index) in ver.FileList:
  439.                 indexfile = self.controller.cache._list.FindIndex(VerFileIter)
  440.                 if indexfile and indexfile.IsTrusted:
  441.                     logging.info("Forcing downgrade of libgl1-mesa-dri for xgl.compz.info installs")
  442.                                 self.controller.cache._depcache.SetCandidateVer(pkg._pkg, ver)
  443.                     break
  444.                                     
  445.         # deal with general if $foo is installed, install $bar
  446.         for (fr, to) in [("xserver-xorg-driver-all","xserver-xorg-video-all")]:
  447.             if self.controller.cache.has_key(fr) and self.controller.cache.has_key(to):
  448.                 if self.controller.cache[fr].isInstalled and not self.controller.cache[to].markedInstall:
  449.                     try:
  450.                         self.controller.cache.markInstall(to,"%s->%s quirk upgrade rule" % (fr, to))
  451.                     except SystemError, e:
  452.                         logging.debug("Failed to apply %s->%s install (%s)" % (fr, to, e))
  453.                     
  454.     def dapperPostDistUpgradeCache(self):
  455.         """ this function works around quirks in the breezy->dapper upgrade """
  456.         logging.debug("running %s" %  sys._getframe().f_code.co_name)
  457.         if (self.controller.cache.has_key("nvidia-glx") and self.controller.cache["nvidia-glx"].isInstalled and
  458.             self.controller.cache.has_key("nvidia-settings") and self.controller.cache["nvidia-settings"].isInstalled):
  459.             logging.debug("nvidia-settings and nvidia-glx is installed")
  460.             self.controller.cache.markRemove("nvidia-settings")
  461.             self.controller.cache.markInstall("nvidia-glx")
  462.  
  463.     def from_hardyPostDistUpgradeCache(self):
  464.         """ this function works around quirks in upgrades from hardy """
  465.         logging.debug("running %s" %  sys._getframe().f_code.co_name)
  466.         # evms got removed after hardy, warn and abort
  467.         if self._usesEvmsInMounts():
  468.             logging.error("evms in use in /etc/fstab")
  469.             self._view.error(_("evms in use"),
  470.                              _("Your system uses the 'evms' volume manager "
  471.                                "in /proc/mounts. "
  472.                                "The 'evms' software is no longer supported, "
  473.                                "please switch it off and run the upgrade "
  474.                                "again when this is done."))
  475.             self.controller.abort()
  476.         # check if a key depends of kubuntu-kde4-desktop is installed
  477.         # and transition in this case as well
  478.         deps_found = False
  479.         frompkg = "kubuntu-kde4-desktop"
  480.         topkg = "kubuntu-desktop"
  481.         if self.config.getlist(frompkg,"KeyDependencies"):
  482.             deps_found = True
  483.             for pkg in self.config.getlist(frompkg,"KeyDependencies"):
  484.                 deps_found &= (self.controller.cache.has_key(pkg) and
  485.                                self.controller.cache[pkg].isInstalled)
  486.         if deps_found:
  487.             logging.debug("transitioning %s to %s (via key depends)" % (frompkg, topkg))
  488.             self.controller.cache[topkg].markInstall()
  489.             
  490.  
  491.     # run right before the first packages get installed
  492.     def StartUpgrade(self):
  493.         self._applyPatches()
  494.         self._removeOldApportCrashes()
  495.         self._removeBadMaintainerScripts()
  496.         self._killUpdateNotifier()
  497.         self._killKBluetooth()
  498.         self._killScreensaver()
  499.         self._stopDocvertConverter()
  500.     def jauntyStartUpgrade(self):
  501.         self._createPycentralPkgRemove()
  502.         # hal/NM triggers problem, if the old (intrepid) hal gets
  503.         # triggered for a restart this causes NM to drop all connections
  504.         # because (old) hal thinks it has no devices anymore (LP: #327053)
  505.         ap = "/var/lib/dpkg/info/hal.postinst"
  506.         if os.path.exists(ap):
  507.             # intrepid md5 of hal.postinst (jaunty one is different)
  508.             # md5 jaunty 22c146857d751181cfe299a171fc11c9
  509.             md5sum = "146145275900af343d990a4dea968d7c"
  510.             if md5(open(ap).read()).hexdigest() == md5sum:
  511.                 logging.debug("removing bad script '%s'" % ap)
  512.                 os.unlink(ap)
  513.     def dapperStartUpgrade(self):
  514.         # check theme, crux is known to fail badly when upgraded 
  515.         # from dapper
  516.         if "DISPLAY" in os.environ and "SUDO_USER" in os.environ:
  517.             out = subprocess.Popen(["sudo","-u", os.environ["SUDO_USER"],
  518.                                     "./theme-switch-helper.py", "-g"],
  519.                                     stdout=subprocess.PIPE).communicate()[0]
  520.             if "Crux" in out:
  521.                 subprocess.call(["sudo","-u", os.environ["SUDO_USER"],
  522.                                     "./theme-switch-helper.py", "--defaults"])
  523.         return True
  524.     # helpers
  525.  
  526.     def _mysqlClusterCheck(self):
  527.         """
  528.         check if ndb clustering is used and do not upgrade mysql
  529.         if it is (LP: #450837)
  530.         """
  531.         logging.debug("_mysqlClusterCheck")
  532.         if (self.controller.cache.has_key("mysql-server") and
  533.             self.controller.cache["mysql-server"].isInstalled):
  534.             # taken from the mysql-server-5.1.preinst
  535.             ret = subprocess.call([
  536.                     "egrep", "-q", "-i", "-r",
  537.                     "^[^#]*ndb.connectstring|^[:space:]*\[[:space:]*ndb_mgmd", 
  538.                     "/etc/mysql/"])
  539.             logging.debug("egrep returned %s" % ret)
  540.             # if clustering is used, do not upgrade to 5.1 and 
  541.             # remove mysql-{server,client}
  542.             # metapackage and upgrade the 5.0 packages
  543.             if ret == 0:
  544.                 logging.debug("mysql clustering in use, do not upgrade to 5.1")
  545.                 for pkg in ("mysql-server", "mysql-client"):
  546.                     self.controller.cache.markRemove(pkg, "clustering in use")
  547.                     # mark mysql-{server,client}-5.0 as manual install (#453513)
  548.                     depcache = self.controller.cache._depcache
  549.                     for pkg in ["mysql-server-5.0", "mysql-client-5.0"]:
  550.                         if pkg.isInstalled and depcache.IsAutoInstalled(pkg._pkg):
  551.                             logging.debug("marking '%s' manual installed" % pkg.name)
  552.                             autoInstDeps = False
  553.                             fromUser = True
  554.                             depcache.MarkInstall(pkg._pkg, autoInstDeps, fromUser)
  555.             else:
  556.                 self.controller.cache.markUpgrade("mysql-server", "no clustering in use")
  557.  
  558.     def _checkArmCPU(self):
  559.         """
  560.         parse /proc/cpuinfo and search for ARMv6 or greater
  561.         """
  562.         logging.debug("checking for ARM CPU version")
  563.         if not os.path.exists("/proc/cpuinfo"):
  564.             logging.error("cannot open /proc/cpuinfo ?!?")
  565.             return False
  566.         cpuinfo = open("/proc/cpuinfo")
  567.         if re.search("^Processor\s*:\s*ARMv[45]", cpuinfo.read(), re.MULTILINE):
  568.             return False
  569.         return True
  570.  
  571.     def _dealWithLanguageSupportTransition(self):
  572.         """
  573.         In karmic the language-support-translations-* metapackages
  574.         are gone and the direct dependencies will get marked for
  575.         auto removal - mark them as manual instead
  576.         """
  577.         logging.debug("language-support-translations-* transition")
  578.         for pkg in self.controller.cache:
  579.             depcache = self.controller.cache._depcache
  580.             if (pkg.name.startswith("language-support-translations") and
  581.                 pkg.isInstalled):
  582.                 for dp_or in pkg.installedDependencies:
  583.                     for dpname in dp_or.or_dependencies:
  584.                         dp = self.controller.cache[dpname.name]
  585.                         if dp.isInstalled and depcache.IsAutoInstalled(dp._pkg):
  586.                             logging.debug("marking '%s' manual installed" % dp.name)
  587.                             autoInstDeps = False
  588.                             fromUser = True
  589.                             depcache.MarkInstall(dp._pkg, autoInstDeps, fromUser)
  590.                             
  591.     def _checkLanguageSupport(self):
  592.         """
  593.         check if the language support is fully installed and if
  594.         not generate a update-notifier note on next login
  595.         """
  596.         if not os.path.exists("/usr/bin/check-language-support"):
  597.             logging.debug("no check-language-support available")
  598.             return
  599.         p = subprocess.Popen(["check-language-support"],stdout=subprocess.PIPE)
  600.         for pkgname in p.communicate()[0].split():
  601.             if (self.controller.cache.has_key(pkgname) and
  602.                 not self.controller.cache[pkgname].isInstalled):
  603.                 logging.debug("language support package '%s' missing" % pkgname)
  604.                 # check if kde/gnome and copy language-selector note
  605.                 base = "/usr/share/language-support/"
  606.                 target = "/var/lib/update-notifier/user.d"
  607.                 for p in ("incomplete-language-support-gnome.note",
  608.                           "incomplete-language-support-qt.note"):
  609.                     if os.path.exists(os.path.join(base,p)):
  610.                         shutil.copy(os.path.join(base,p), target)
  611.                         return
  612.  
  613.     def _checkAndInstallBroadcom(self):
  614.         """
  615.         check for the 'wl' kernel module and install bcmwl-kernel-source
  616.         if the module is loaded
  617.         """
  618.         logging.debug("checking for 'wl' module")
  619.         if "wl" in lsmod():
  620.             self.controller.cache.markInstall("bcmwl-kernel-source",
  621.                                               "'wl' module found in lsmod")
  622.  
  623.     def _stopDocvertConverter(self):
  624.         " /etc/init.d/docvert-converter stop (see bug #450569)"
  625.         # kill update-notifier now to suppress reboot required
  626.         if os.path.exists("/etc/init.d/docvert-converter"):
  627.             logging.debug("/etc/init.d/docvert-converter stop")
  628.             subprocess.call(["/etc/init.d/docvert-converter","stop"])
  629.     def _killUpdateNotifier(self):
  630.         "kill update-notifier"
  631.         # kill update-notifier now to suppress reboot required
  632.         if os.path.exists("/usr/bin/killall"):
  633.             logging.debug("killing update-notifier")
  634.             subprocess.call(["killall","-q","update-notifier"])
  635.     def _killKBluetooth(self):
  636.         """killall kblueplugd kbluetooth (riddel requested it)"""
  637.         if os.path.exists("/usr/bin/killall"):
  638.             logging.debug("killing kblueplugd kbluetooth4")
  639.             subprocess.call(["killall", "-q", "kblueplugd", "kbluetooth4"])
  640.     def _killScreensaver(self):
  641.         """killall gnome-screensaver """
  642.         if os.path.exists("/usr/bin/killall"):
  643.             logging.debug("killing gnome-screensaver")
  644.             subprocess.call(["killall", "-q", "gnome-screensaver"])
  645.     def _removeBadMaintainerScripts(self):
  646.         " remove bad/broken maintainer scripts (last resort) "
  647.         # apache: workaround #95325 (edgy->feisty)
  648.         # pango-libthai #103384 (edgy->feisty)
  649.         bad_scripts = ["/var/lib/dpkg/info/apache2-common.prerm",
  650.                        "/var/lib/dpkg/info/pango-libthai.postrm",
  651.                        ]
  652.         for ap in bad_scripts:
  653.             if os.path.exists(ap):
  654.                 logging.debug("removing bad script '%s'" % ap)
  655.                 os.unlink(ap)
  656.  
  657.     def _createPycentralPkgRemove(self):
  658.         """
  659.         intrepid->jaunty, create /var/lib/pycentral/pkgremove flag file
  660.         to help python-central so that it removes all preinst links
  661.         on upgrade
  662.         """
  663.         logging.debug("adding pkgremove file")
  664.         if not os.path.exists("/var/lib/pycentral/"):
  665.             os.makedirs("/var/lib/pycentral")
  666.         open("/var/lib/pycentral/pkgremove","w")
  667.  
  668.     def _removeOldApportCrashes(self):
  669.         " remove old apport crash files "
  670.         try:
  671.             for f in glob.glob("/var/crash/*.crash"):
  672.                 logging.debug("removing old crash file '%s'" % f)
  673.                 os.unlink(f)
  674.         except Exception, e:
  675.             logging.warning("error during unlink of old crash files (%s)" % e)
  676.  
  677.     def _cpuHasSSESupport(self, cpuinfo="/proc/cpuinfo"):
  678.         " helper that checks if the given cpu has sse support "
  679.         if not os.path.exists(cpuinfo):
  680.             return False
  681.         for line in open(cpuinfo):
  682.             if line.startswith("flags") and not " sse" in line:
  683.                 return False
  684.         return True
  685.  
  686.     def _usesEvmsInMounts(self):
  687.         " check if evms is used in /proc/mounts "
  688.         logging.debug("running _usesEvmsInMounts")
  689.         for line in open("/proc/mounts"):
  690.             line = line.strip()
  691.             if line == '' or line.startswith("#"):
  692.                 continue
  693.             try:
  694.                 (device, mount_point, fstype, options, a, b) = line.split()
  695.             except Exception, e:
  696.                 logging.error("can't parse line '%s'" % line)
  697.                 continue
  698.             if "evms" in device:
  699.                 logging.debug("found evms device in line '%s', skipping " % line)
  700.                 return True
  701.         return False
  702.  
  703.     def _checkAndRemoveEvms(self):
  704.         " check if evms is in use and if not, remove it "
  705.         logging.debug("running _checkAndRemoveEvms")
  706.         if self._usesEvmsInMounts():
  707.             return False
  708.         # if not in use, nuke it
  709.         for pkg in ["evms","libevms-2.5","libevms-dev",
  710.                     "evms-ncurses", "evms-ha",
  711.                     "evms-bootdebug",
  712.                     "evms-gui", "evms-cli",
  713.                     "linux-patch-evms"]:
  714.             if self.controller.cache.has_key(pkg) and self.controller.cache[pkg].isInstalled:
  715.                 self.controller.cache[pkg].markDelete()
  716.         return True
  717.  
  718.     def _addRelatimeToFstab(self):
  719.         " add the relatime option to ext2/ext3 filesystems on upgrade "
  720.         logging.debug("_addRelatime")
  721.         replaced = False
  722.         lines = []
  723.         for line in open("/etc/fstab"):
  724.             line = line.strip()
  725.             if line == '' or line.startswith("#"):
  726.                 lines.append(line)
  727.                 continue
  728.             try:
  729.                 (device, mount_point, fstype, options, a, b) = line.split()
  730.             except Exception, e:
  731.                 logging.error("can't parse line '%s'" % line)
  732.                 lines.append(line)
  733.                 continue
  734.             if (("ext2" in fstype or
  735.                  "ext3" in fstype) and 
  736.                 (not "noatime" in options) and
  737.                 (not "relatime" in options) ):
  738.                 logging.debug("adding 'relatime' to line '%s' " % line)
  739.                 line = line.replace(options,"%s,relatime" % options)
  740.                 logging.debug("replaced line is '%s' " % line)
  741.                 replaced=True
  742.             lines.append(line)
  743.         # we have converted a line
  744.         if replaced:
  745.             logging.debug("writing new /etc/fstab")
  746.             f=open("/etc/fstab.intrepid","w")
  747.             f.write("\n".join(lines))
  748.             # add final newline (see LP: #279093)
  749.             f.write("\n")
  750.             f.close()
  751.             os.rename("/etc/fstab.intrepid","/etc/fstab")
  752.         return True
  753.         
  754.     def _ntfsFstabFixup(self, fstab="/etc/fstab"):
  755.         """change PASS 1 to 0 for ntfs entries (#441242)"""
  756.         logging.debug("_ntfsFstabFixup")
  757.         replaced = False
  758.         lines = []
  759.         for line in open(fstab):
  760.             line = line.strip()
  761.             if line == '' or line.startswith("#"):
  762.                 lines.append(line)
  763.                 continue
  764.             try:
  765.                 (device, mount_point, fstype, options, fdump, fpass) = line.split()
  766.             except Exception, e:
  767.                 logging.error("can't parse line '%s'" % line)
  768.                 lines.append(line)
  769.                 continue
  770.             if ("ntfs" in fstype and fpass == "1"):
  771.                 logging.debug("changing PASS for ntfs to 0 for '%s' " % line)
  772.                 if line[-1] == "1":
  773.                     line = line[:-1] + "0"
  774.                 else:
  775.                     logging.error("unexpected value in line")
  776.                 logging.debug("replaced line is '%s' " % line)
  777.                 replaced=True
  778.             lines.append(line)
  779.         # we have converted a line
  780.         if replaced:
  781.             suffix = ".jaunty"
  782.             logging.debug("writing new /etc/fstab")
  783.             f=open(fstab + suffix, "w")
  784.             f.write("\n".join(lines))
  785.             # add final newline (see LP: #279093)
  786.             f.write("\n")
  787.             f.close()
  788.             os.rename(fstab+suffix, fstab)
  789.         return True
  790.         
  791.  
  792.     def _rewriteFstab(self):
  793.         " convert /dev/{hd?,scd0} to /dev/cdrom for the feisty upgrade "
  794.         logging.debug("_rewriteFstab()")
  795.         replaced = 0
  796.         lines = []
  797.         # we have one cdrom to convert
  798.         for line in open("/etc/fstab"):
  799.             line = line.strip()
  800.             if line == '' or line.startswith("#"):
  801.                 lines.append(line)
  802.                 continue
  803.             try:
  804.                 (device, mount_point, fstype, options, a, b) = line.split()
  805.             except Exception, e:
  806.                 logging.error("can't parse line '%s'" % line)
  807.                 lines.append(line)
  808.                 continue
  809.             # edgy kernel has /dev/cdrom -> /dev/hd?
  810.             # feisty kernel (for a lot of chipsets) /dev/cdrom -> /dev/scd0
  811.             # this breaks static mounting (LP#86424)
  812.             #
  813.             # we convert here to /dev/cdrom only if current /dev/cdrom
  814.             # points to the device in /etc/fstab already. this ensures
  815.             # that we don't break anything or that we get it wrong
  816.             # for systems with two (or more) cdroms. this is ok, because
  817.             # we convert under the old kernel
  818.             if ("iso9660" in fstype and
  819.                 device != "/dev/cdrom" and
  820.                 os.path.exists("/dev/cdrom") and
  821.                 os.path.realpath("/dev/cdrom") == device
  822.                 ):
  823.                 logging.debug("replacing '%s' " % line)
  824.                 line = line.replace(device,"/dev/cdrom")
  825.                 logging.debug("replaced line is '%s' " % line)
  826.                 replaced += 1
  827.             lines.append(line)
  828.         # we have converted a line (otherwise we would have exited already)
  829.         if replaced > 0:
  830.             logging.debug("writing new /etc/fstab")
  831.             shutil.copy("/etc/fstab","/etc/fstab.edgy")
  832.             f=open("/etc/fstab","w")
  833.             f.write("\n".join(lines))
  834.             # add final newline (see LP: #279093)
  835.             f.write("\n")
  836.             f.close()
  837.         return True
  838.  
  839.     def _checkAdminGroup(self):
  840.         " check if the current sudo user is in the admin group "
  841.         logging.debug("_checkAdminGroup")
  842.         import grp
  843.         try:
  844.             admin_group = grp.getgrnam("admin").gr_mem
  845.         except KeyError, e:
  846.             logging.warning("System has no admin group (%s)" % e)
  847.             subprocess.call(["addgroup","--system","admin"])
  848.         # double paranoia
  849.         try:
  850.             admin_group = grp.getgrnam("admin").gr_mem
  851.         except KeyError, e:
  852.             logging.warning("adding the admin group failed (%s)" % e)
  853.             return
  854.         # if the current SUDO_USER is not in the admin group
  855.         # we add him - this is no security issue because
  856.         # the user is already root so adding him to the admin group
  857.         # does not change anything
  858.         if (os.environ.has_key("SUDO_USER") and
  859.             not os.environ["SUDO_USER"] in admin_group):
  860.             admin_user = os.environ["SUDO_USER"]
  861.             logging.info("SUDO_USER=%s is not in admin group" % admin_user)
  862.             cmd = ["usermod","-a","-G","admin",admin_user]
  863.             res = subprocess.call(cmd)
  864.             logging.debug("cmd: %s returned %i" % (cmd, res))
  865.  
  866.     def _checkVideoDriver(self, name):
  867.         " check if the given driver is in use in xorg.conf "
  868.         XORG="/etc/X11/xorg.conf"
  869.         if not os.path.exists(XORG):
  870.             return False
  871.         for line in open(XORG):
  872.             s=line.split("#")[0].strip()
  873.             # check for fglrx driver entry
  874.             if (s.lower().startswith("driver") and
  875.                 s.endswith('"%s"' % name)):
  876.                 return True
  877.         return False
  878.  
  879.     def _applyPatches(self, patchdir="./patches"):
  880.         """
  881.         helper that applies the patches in patchdir. the format is
  882.         _path_to_file.md5sum
  883.         
  884.         and it will apply the diff to that file if the md5sum
  885.         matches
  886.         """
  887.         if not os.path.exists(patchdir):
  888.             logging.debug("no patchdir")
  889.             return
  890.         if not ("PATH" in os.environ and
  891.                 [p for p in os.environ["PATH"].split(":")
  892.                  if os.path.exists(os.path.join(p,"sed"))]):
  893.             logging.debug("no binary 'sed' found in PATH")
  894.             return
  895.         for f in os.listdir(patchdir):
  896.             # skip, not a patch file, they all end with .$md5sum
  897.             if not "." in f:
  898.                 logging.debug("skipping '%s' (no '.')" % f)
  899.                 continue
  900.             logging.debug("check if patch '%s' needs to be applied" % f)
  901.             (encoded_path, md5sum) = string.rsplit(f, ".", 1)
  902.             # FIXME: this is not clever and needs quoting support for
  903.             #        filenames with "_" in the name
  904.             path = encoded_path.replace("_","/")
  905.             #logging.debug("target for '%s' is '%s' -> '%s'" % (
  906.             #        f, encoded_path, path))
  907.             if (os.path.exists(path) and
  908.                 md5(open(path).read()).hexdigest() == md5sum):
  909.                 logging.info("applying '%s'" % f)
  910.                 # dry-run first, then patch if ok
  911.                 cmd = ["sed","-n", "-f", patchdir+"/"+f, path]
  912.                 logging.debug("runing '%s'" % cmd)
  913.                 res = call(cmd)
  914.                 if res == 0:
  915.                     res = call(["sed","-i","-f", patchdir+"/"+f, path])
  916.                     logging.info("applied '%s' with %i status" % (f,res))
  917.                 else:
  918.                     logging.warning("dry run failed, ignoring patch '%s'" % f)
  919.                     
  920.     def _supportInModaliases(self, xorgdrivername, modaliasesdir="./modaliases", lspci=None):
  921.         """ 
  922.         Check if xorgdriver will work on this hardware
  923.  
  924.         This helper will check with the modaliasesdir if the given 
  925.         xorgdriver will work on this hardware (or the hardware given
  926.         via the lspci argument)
  927.         """
  928.         if not lspci:
  929.             lspci = set()
  930.             p = subprocess.Popen(["lspci","-n"],stdout=subprocess.PIPE)
  931.             for line in p.communicate()[0].split("\n"):
  932.                 if line:
  933.                     lspci.add(line.split()[2])
  934.         for filename in os.listdir(modaliasesdir):
  935.             #logging.debug("modalias file '%s'" % filename)
  936.             for line in open(os.path.join(modaliasesdir,filename)):
  937.                 line = line.strip()
  938.                 if line == "" or line.startswith("#"):
  939.                     continue
  940.                 (key, pciid, xorgdriver, pkgname) = line.split()
  941.                 if xorgdriver != xorgdrivername:
  942.                     continue
  943.                 m = re.match("pci:v0000(.+)d0000(.+)sv.*", pciid)
  944.                 if m:
  945.                     matchid = "%s:%s" % (m.group(1), m.group(2))
  946.                     if matchid.lower() in lspci:
  947.                         logging.debug("found system pciid '%s' in modaliases" % matchid)
  948.                         return True
  949.         logging.debug("checking for %s support in modaliases but none found" % xorgdrivername)
  950.         return False
  951.                     
  952.  
  953.     def _kernel386TransitionCheck(self):
  954.         """ test if the current kernel is 386 and if the system is 
  955.             capable of using a generic one instead (#353534)
  956.         """
  957.         logging.debug("_kernel386TransitionCheck")
  958.         # we test first if one of 386 is installed
  959.         # if so, check if the system could also work with -generic
  960.         # (we get that from base-installer) and try to installed
  961.         #  that)
  962.         for pkgname in ["linux-386", "linux-image-386"]:
  963.             if (self.controller.cache.has_key(pkgname) and
  964.                 self.controller.cache[pkgname].isInstalled):
  965.                 working_kernels = self.controller.cache.getKernelsFromBaseInstaller()
  966.                 upgrade_to = ["linux-generic", "linux-image-generic"]
  967.                 for pkgname in upgrade_to:
  968.                     if pkgname in working_kernels:
  969.                         logging.debug("386 kernel installed, but generic kernel  will work on this machine")
  970.                         if self.controller.cache.markInstall(pkgname, "386 -> generic transition"):
  971.                             return
  972.         
  973.  
  974.  
  975.